/**
 * 定义时间轴的顶级类
 * */
import { CONTEXT_MENU, DOUBLE_DRIVER_POS, ICON_STATUS, VTUBER_COUNT_TYPE } from '../js/enums';
import {
  calcNewSelect,
  calcSpectrumWorker,
  getAudioDuration,
} from '@veditor/components/timeLine/js/common';
import ChartManager from '@veditor/utils/ChartManager';
import {
  addBufferWavHeader,
  base64ToAb,
  generateUUID,
  getBlobByUrl,
} from '@veditor/components/timeLine/js/tools';

// 顶级类
class TimeLine {
  id = null;
  zIndex = 0; // 层级
  startTime = 0; // 开始时间
  duration = 0; // 时长
  videoDuration = 0; // 视频的时长
  loop = false; // 是否循环
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  }; // 禁止
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 1, // 0:禁止 1:有声 2.禁止声音
    contract: 0, // 0:禁止 1.展开 2.收缩
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中, 这个是全部禁用的标志,如果是2,则编辑操作全部禁用
  }; // 图标的展示和隐藏
  name = '';
  mark = ''; // 用于表示是由组件来的,后续用来对应组件
  allTime = false; // 全局时间显示
  multi = false; // 是否是多元素一轴
  multiBlock = false; // 一元素多块显示,只适用于一轴单元素
  sliderArr = []; // 一行多元素用来存储数据的模块,有startTime和duration,disable单元素不使用
  blockArr = []; // 普通元素只显示一块,视频元素显示多块,里面也有startTime,duration
  contextMenuList = []; // 右键菜单列表
  sliderArrCallback = []; // sliderArr改变的回调,触发页面更新
  // 用于集成子类轴的功能
  fatherName = '';
  fatherStartTime = 0; // 父元素的开始时间,后续多轴元素计算需要加上
  fatherEl = null; // 用于子轴保存父元素的指针
  childrenList = []; // 子元素的列表:名称
  childrenElList = []; // 子元素的本体
  currentSelect = -1; // 当前选中的元素
  playing = false; // 当前播放状态
  backUpAttr = null; // 用于备份之前的属性
  partUpdateAttr = []; // 指定局部更新时需要更新的属性,后续新增的属性一定要考虑局部更新是否需要添加属性到这里
  constructor(params) {
    this._parseParams(params);
  }
  // 计算元素块
  calcBlockArr(lineWidth, allWidth) {
    const { multi, multiBlock, blockArr } = this;
    const { originDuration, videoDuration } = this;
    // multi 多元素轴和 multiBlock 为 false的轴数据处理是一样的,都是只展示一个
    // 里面的每个元素只有比例的概念|startTime endTIme(这样的话父元素移动需要计算所有子元素位置)
    const duration = (lineWidth / allWidth) * videoDuration; // 算出当前时间
    blockArr.splice(0, blockArr.length);
    if (multi || !multiBlock) {
      blockArr.push({ width: lineWidth });
    } else if (multiBlock) {
      const val = duration / originDuration;
      const residue = duration % originDuration; // 剩余长度
      if (val <= 1) {
        blockArr.push({ width: lineWidth });
      } else {
        for (let i = 0; i < Math.floor(val); i++) {
          blockArr.push({ width: lineWidth * (originDuration / duration) });
        }
        if (residue > 0) {
          blockArr.push({ width: lineWidth * (residue / duration) });
        }
      }
    }
  }
  // 用于赋值参数
  _parseParams(params) {
    const {
      zIndex,
      startTime = 0,
      id,
      duration = 0,
      videoDuration = 0,
      loop = false,
      mark,
      allTime = false,
    } = params;
    Object.assign(this, { zIndex, startTime, id, duration, videoDuration, loop, mark, allTime });
  }
  // 用于解析音量,私有方法
  _parseIconConfig(params) {
    const { iconDisable } = this;
    const { vol = 0, visible = true, selectable: select = true } = params;
    const sound = vol > 0 ? 1 : 2;
    const show = visible ? 1 : 2;
    const selectable = select ? 1 : 2;
    if (iconDisable.sound !== 0) {
      iconDisable.sound = sound;
    }
    if (iconDisable.show !== 0) {
      iconDisable.show = show;
    }
    if (iconDisable.selectable !== 0) {
      iconDisable.selectable = selectable;
      // 更新元素的selectable状态
      if (selectable === ICON_STATUS.OFF) {
        this._disableAll();
      } else {
        this.backUpAttr && this._backDisable();
      }
    }
  }
  // 用于计算计算startTime占所有时长的占比,然后得到宽度,针对一轴单元素的
  calcPosition(width, startTime, duration) {
    const { videoDuration } = this;
    const rate = duration / videoDuration;
    // const realRate = rate > 1 ? 1 : rate; // 防止当前元素的比例超出
    const beforeRate = startTime / videoDuration;
    const lineWidth = rate * width;
    const leftWidth = beforeRate * width; // 2px用于防止元素离得太近,看不出中间的间隔
    this.calcBlockArr(lineWidth, width);
    return {
      width: lineWidth,
      left: leftWidth,
    };
  }
  // 提供一个直接更改数组的更新方法
  updateDataByArr(dragItemList, allWidth) {
    const arr = [];
    const { videoDuration, multi, sliderArr, childrenList, fatherStartTime } = this;
    dragItemList.forEach(item => {
      const { uid, lineStyle } = item;
      const { left, width } = lineStyle;
      const startTime = Number(((left / allWidth) * videoDuration).toFixed(Number('3')));
      const duration = Number(((width / allWidth) * videoDuration).toFixed(Number('3')));
      if (multi) {
        // 找到对应的元素
        const sliderItem = sliderArr.find(i => i.uid === uid);
        Object.assign(sliderItem, { startTime: startTime + fatherStartTime, duration });
        arr.push(sliderItem);
      } else {
        Object.assign(this, { startTime, duration });
        this.changeTime(this);
      }
    });
    // 这里先更新数据
    if (multi) {
      sliderArr.splice(0, sliderArr.length);
      sliderArr.push(...arr);
    }
    this._handleChildrenUpdateLink(); // 这里依赖上边的数据更新
    // 这里再发送更新指令
    if (multi) {
      this.changeOrder(this);
    }
    // 有子元素需要更新子元素的时长
    if (childrenList.length) {
      this._handleFatherUpdate(true);
    }
  }
  // 用于处理子轴更新时长时父轴的联动效果
  _handleChildrenUpdateLink() {
    const { fatherEl, fatherName } = this;
    if (fatherName) {
      const range = {};
      const exceedFlag = this._handleFindFatherRange(range);
      if (exceedFlag) {
        Object.assign(fatherEl, range);
        fatherEl._handleFatherUpdate(false);
        fatherEl.changeTime(fatherEl);
        // fatherEl.handleSliderArrChange();
        // this.handleSliderArrChange();
      }
    }
  }
  // 用于子元素寻找父元素的边界
  _handleFindFatherRange(range) {
    const { fatherEl } = this;
    const { startTime: fs, duration: fd } = fatherEl;
    const DRIVER_LIST = ['textDrive', 'audioDrive', 'doubleDrive'];
    let startTime = Number.MAX_VALUE,
      endTime = 0,
      modifyFlag = false;
    fatherEl.childrenElList.forEach(item => {
      const { sliderArr, name, startTime: is, duration: id } = item;
      if (!DRIVER_LIST.includes(name)) {
        return;
      }
      const { startTime: ss, duration: sd } = sliderArr[0];
      const { startTime: ls, duration: ld } = sliderArr[sliderArr.length - 1];
      if (ss < startTime) {
        startTime = ss;
      }
      if (ld + ls > endTime) {
        endTime = ld + ls;
      }
    });
    Object.assign(range, { startTime, duration: endTime - startTime });
    modifyFlag = !(range.startTime === fs && range.duration === fd);
    return modifyFlag;
  }
  // 用于父元素更新时长
  _handleFatherUpdate(isUpdate) {
    const { startTime, childrenElList } = this;
    childrenElList.forEach(item => {
      const { fatherStartTime, sliderArr } = item;
      item.fatherStartTime = startTime;
      if (isUpdate) {
        const offset = startTime - fatherStartTime;
        sliderArr.forEach(item => (item.startTime += offset));
        if (item.multi) {
          item.changeOrder(item);
        } else {
          item.changeTime(item);
        }
      }
      // item.handleSliderArrChange();
    });
  }
  // 用来提交单元素改变顺序
  calcTime() {
    const { startTime, duration, mark, name } = this;
    return { mark, startTime, duration, name };
  }
  // 用于更新video时长
  updateVideoDuration(videoDuration) {
    this.videoDuration = videoDuration;
    if (this.allTime) {
      this.duration = videoDuration;
    }
    this.videoDurationChange(); // 用于各个处理视频总时长的变化
  }
  // 处理全时长的数据初始化
  _initAllTime() {
    if (this.allTime) {
      this.duration = this.videoDuration;
      this.startTime = 0;
    }
  }
  // 用于对不同的点击按钮事件进行处理此
  parseClickIcon(type) {
    const { name, mark, disable, iconDisable } = this;
    const canClick = !disable.clickIcon && iconDisable[type]; // 可以点击左侧按钮并且当前点击的是可点击的
    if (canClick) {
      const status = iconDisable[type];
      return { mark, name, type, status };
    } else {
      return { mark: '', name: '', type: '' };
    }
  }
  // 解析menuList
  parseContextMenu() {
    return this.contextMenuList.map(item => CONTEXT_MENU[item]);
  }
  // 用于处理播放状态改变
  updatePlaying(val) {
    this.playing = val;
  }
  // 处理删除多轴元素currentSelect变化
  handleClickMenu(index, value) {
    const AUTO_CALC_ARR = ['action', 'background3d', 'camera', 'emotion'];
    if (value === 'delete') {
      const { multi, currentSelect, sliderArr, name } = this;
      // 这里有白名单,这个自动计算只对个别轴生效
      if (multi && currentSelect !== -1 && AUTO_CALC_ARR.find(item => item === name)) {
        this.currentSelect = calcNewSelect(index, currentSelect, sliderArr.length); // 对于多轴元素删除某一个元素currentSelect的变化
        this.select(this, this.currentSelect);
        this.sliderArr.splice(index, 1); // 有顺序关系,不要修改
      }
    }
  }
  // 禁用全部功能 两种禁用方式 1.不用中禁用,结束自动取消2.锁禁用,可以手动解锁
  _disableAll(type = 'lock') {
    const { disable, iconDisable } = this;
    const disableCopy = JSON.parse(JSON.stringify(disable));
    const iconDisableCopy = JSON.parse(JSON.stringify(iconDisable));
    this.backUpAttr = {
      disable: disableCopy,
      iconDisable: iconDisableCopy,
    };
    const DISABLE_WHITE = ['clickIcon', 'previewVideo']; // 禁用的白名单
    for (const key in this.disable) {
      if (!DISABLE_WHITE.includes(key)) {
        this.disable[key] = true;
      }
    }
    for (const key in this.iconDisable) {
      // 注意这里不能禁用自己,不然没有解锁了
      if ((type !== 'lock' || key !== 'selectable') && key !== 'contract') {
        this.iconDisable[key] = ICON_STATUS.DIS;
      }
    }
  }
  // 回退禁用的属性
  _backDisable() {
    Object.assign(this, this.backUpAttr);
    this.backUpAttr = null;
  }
  // 用于把时间转换为px
  transformTimeToPx(time, allWidth) {
    return (time / this.videoDuration) * allWidth;
  }
  // 专用于更新父轴的方法
  videoDurationChange() {}
  // 坑位:只更新lineItem里面数据的方法
  resize() {}
  //坑位:这个是更新时长的回调函数
  changeTime(item) {}
  // 坑位:用来存储元素双击时间轴的事件
  dbClick() {}
  // 坑位:用来存储元素单击选中的事件
  clickItem() {}
  // 坑位:用来存储元素单击图标的事件
  clickIcon() {}
  // 坑位:用于处理时间轴右键菜单的事件
  clickMenu() {}
  // 坑位:用于更新所有的sliderArr数据变化的回调,类似vue的监察者模式
  handleSliderArrChange() {
    const { sliderArrCallback } = this;
    sliderArrCallback.forEach(item => {
      item();
    });
  }
  // 坑位:改变同轴多元素的顺序
  changeOrder() {}
  // 坑位:用来回调选中时间轴
  select() {}
  // 坑位:用于子轴控制滚动条滚动
  changeScroll() {}
  // 坑位:显示预览弹窗
  openPreview() {
    return false;
  }
  // 坑位:隐藏预览弹窗
  closePreview() {
    return false;
  }
  // 用于更新父轴数据的方法
  onVideoDuration() {}
}
// 虚拟人类
class Vtuber extends TimeLine {
  allTime = false;
  name = 'vtuber';
  vtuberName = '';
  vtuberSrc = '';
  disable = {
    row: false,
    col: false,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 1, // 0:禁止 1.展开 2.收缩,
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  countType = VTUBER_COUNT_TYPE.SINGLE;
  type = 'normal'; // 两种虚拟人 normal:正常 real:超写实 did:仿真数字人
  childrenList = ['textDrive', 'audioDrive', 'action', 'emotion', 'doubleDrive'];
  contextMenuList = ['delete'];
  partUpdateAttr = ['vtuberName', 'vtuberSrc', 'countType', 'type'];
  constructor(params) {
    super(params);
    const { vtuberName = '', vtuberSrc = '', countType = 0, type = 'normal' } = params;
    Object.assign(this, { vtuberName, vtuberSrc, countType, type });
    // this.allTime = countType === VTUBER_COUNT_TYPE.SINGLE; // 用于但是是allTime,多人是自由拖拽
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 背景音乐类
class BgMusic extends TimeLine {
  name = 'bgMusic';
  musicName = '';
  musicSrc = '';
  musicDuration = 0;
  disable = {
    row: true,
    col: true,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 1, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  sliderArr = []; // 多元素的列表
  multi = true;
  contextMenuList = ['delete'];
  allTime = true;
  partUpdateAttr = ['musicName', 'musicSrc', 'musicDuration', 'sliderArr'];
  constructor(params) {
    super(params);
    const { musicName = '', musicSrc = '', musicDuration = 0 } = params;
    Object.assign(this, { musicName, musicSrc, musicDuration });
    this._initAllTime();
    this._parseIconConfig(params);
    this._parseDuration().then(() => {
      this._generateSliderArr(); // 这里用来解析生成sliderArr
      this.resize();
    }); // 背景音乐轴需要单独解析duration,对于传递默认值得数据进行前端的时长解析
  }
  // 渲染频谱图
  async renderSpectrum(allWidth) {
    const MAX_HEIGHT = 38; // 最大柱形高度
    const PADDING_WIDTH = 8;
    const { sliderArr } = this;
    const renderWidth = allWidth * sliderArr[0].rate - PADDING_WIDTH;
    return await calcSpectrumWorker(renderWidth, MAX_HEIGHT, this.musicSrc, null);
  }
  // 根据时长计算有多少个片段
  _generateSliderArr() {
    const { duration: comDuration, sliderArr, musicName, loop, musicDuration } = this;
    sliderArr.splice(0, sliderArr.length);
    let startTime = 0,
      duration = musicDuration,
      index = 0;
    if (loop) {
      while (true) {
        if (startTime + duration >= comDuration) {
          duration = comDuration - startTime;
          sliderArr.push({
            startTime,
            duration,
            name: `${musicName}${index + 1}`,
            rate: duration / comDuration,
          });
          break;
        } else {
          sliderArr.push({
            startTime,
            duration,
            name: `${musicName}${index + 1}`,
            rate: duration / comDuration,
          });
        }
        index++;
        startTime = startTime + duration;
      }
    } else {
      // 这里判断一下背景音乐市场是否超出视频时长
      const realDuration = duration > comDuration ? comDuration : duration;
      sliderArr.push({
        startTime: 0,
        duration: realDuration,
        name: `${musicName}${index + 1}`,
        rate: realDuration / comDuration,
      });
    }
  }
  // 当时长变化时的处理
  videoDurationChange() {
    this._generateSliderArr();
  }
  // 获取音频的时长
  async _parseDuration() {
    const DEFAULT_DURATION = 10;
    try {
      if (this.musicDuration === DEFAULT_DURATION) {
        const musicAbArr = await getBlobByUrl(this.musicSrc);
        this.musicDuration = await getAudioDuration(musicAbArr);
      }
    } catch (e) {
      if (e === 'timeout') {
        console.log('获取背景音乐时长超时');
      } else {
        console.log('获取背景数据失败');
      }
    }
  }
}
// 贴纸类
class Sticker extends TimeLine {
  name = 'sticker';
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  stickersName = ''; // 贴纸名称
  contextMenuList = ['copy', 'delete'];
  partUpdateAttr = ['stickersName'];
  constructor(params) {
    super(params);
    this.stickersName = params.stickersName;
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 花字类
class Signature extends TimeLine {
  name = 'signature';
  signatureName = ''; // 花字名称
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['copy', 'delete'];
  partUpdateAttr = ['signatureName'];
  constructor(params) {
    super(params);
    this.signatureName = params.signatureName || '';
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 图片类
class Graphics extends TimeLine {
  name = 'graphics';
  graphicsSrc = ''; // 图片地址
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['copy', 'delete'];
  partUpdateAttr = ['graphicsSrc'];
  constructor(params) {
    super(params);
    this.graphicsSrc = params.graphicsSrc || '';
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 视频类
class VideoType extends TimeLine {
  name = 'videoType';
  videoSrc = ''; // 视频地址
  coverSrc = ''; // 封面地址
  originDuration = ''; // 原本的时长
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 1, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['copy', 'delete'];
  multiBlock = true; // 单元素多块
  partUpdateAttr = ['videoSrc', 'coverSrc', 'originDuration'];
  constructor(params) {
    super(params);
    this.videoSrc = params.videoSrc || '';
    this.coverSrc = params.coverSrc || '';
    this.originDuration = params.originDuration || '';
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 形状
class Shape extends TimeLine {
  name = 'shape';
  shapeName = ''; // 图片地址
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['copy', 'delete'];
  partUpdateAttr = ['shapeName'];
  constructor(params) {
    super(params);
    this.shapeName = params.shapeName || '';
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 3D背景
class Background3d extends TimeLine {
  name = 'background3d';
  sliderArr = []; // 滑块列表
  disable = {
    row: false,
    col: true,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  };
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  }; // 图标的展示和隐藏
  multi = true;
  contextMenuList = ['copy', 'delete', 'deleteAll'];
  partUpdateAttr = ['sliderArr'];
  constructor(params) {
    super(params);
    const { bgTimeLine } = params;
    this.sliderArr = this._parseActionList(bgTimeLine);
    this._initAllTime();
    this._parseIconConfig(params);
  }
  // 这里需要对单轴多元素进行解析
  _parseActionList(actionTimeLine) {
    const res = [];
    actionTimeLine.forEach((item, index) => {
      const { startTime, name, duration, thumbnailUrl, url, backgroundType } = item;
      const disable = { row: false, time: false };
      backgroundType === 'movie' && (disable.time = true); // 视频的话禁止修改时长
      res.push({
        startTime,
        name,
        duration,
        thumbnailUrl: backgroundType === 'movie' ? thumbnailUrl : url,
        index,
        uid: generateUUID(),
        disable, // 这里需要添加判断,如果是
      });
    });
    return res;
  }
}
// 相机轴
class Camera extends TimeLine {
  name = 'camera';
  sliderArr = []; // 滑块列表
  disable = {
    row: false,
    col: true,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  }; // 图标的展示和隐藏
  multi = true;
  contextMenuList = ['copy', 'delete', 'deleteAll'];
  partUpdateAttr = ['sliderArr'];
  constructor(params) {
    super(params);
    this.sliderArr = this._parseActionList(params.cameraTimeLine);
    this._initAllTime();
  }
  // 这里需要对单轴多元素进行解析
  _parseActionList(cameraTimeLine) {
    const res = [];
    cameraTimeLine.forEach((item, index) => {
      const { startTime, name, duration, thumbnailUrl } = item;
      res.push({
        startTime,
        name,
        duration,
        thumbnailUrl,
        index,
        uid: generateUUID(),
      });
    });
    return res;
  }
}
// 虚拟人动作
class Action extends TimeLine {
  name = 'action';
  sliderArr = []; // 滑块列表
  disable = {
    row: false,
    col: true,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.展开 2.收缩
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  }; // 图标的展示和隐藏
  multi = true;
  contextMenuList = ['copy', 'delete', 'deleteAll'];
  fatherName = 'vtuber';
  fatherStartTime = 0;
  partUpdateAttr = ['sliderArr'];
  constructor(params) {
    super(params);
    this.sliderArr = this._parseActionList(params.actionTimeLine);
    this._initAllTime();
  }
  // 这里需要对单轴多元素进行解析
  _parseActionList(actionTimeLine) {
    const res = [];
    actionTimeLine.forEach((item, index) => {
      const { startTime, action, duration, thumbnailUrl } = item;
      res.push({
        startTime,
        action,
        duration,
        thumbnailUrl,
        index,
        uid: generateUUID(),
      });
    });
    return res;
  }
}
// 文字驱动轴
class TextDrive extends TimeLine {
  name = 'textDrive';
  baseStartTime = 0;
  disable = {
    row: true,
    col: true,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  }; // 图标的展示和隐藏
  sliderArr = []; // 多元素的列表
  multi = true;
  static SECTION_SIGN = ['。', '.'];
  fatherName = 'vtuber';
  fatherStartTime = 0;
  partUpdateAttr = ['sliderArr', 'baseStartTime'];
  constructor(params) {
    super(params);
    const { voiceTime, baseStartTime, voiceData } = params;
    Object.assign(this, { baseStartTime });
    this._initAllTime();
    this._parseIconConfig(params);
    const voiceAB = voiceData.slice(0, voiceData.byteLength - Number('44')); // 这里对wav减去44长度的头部
    this._generateSliderArr(voiceTime, voiceAB); // 这里用来解析生成sliderArr
  }
  // 根据时长计算有多少个片段
  _generateSliderArr(voiceTime, voiceAB) {
    const { baseStartTime } = this;
    const res = [];
    let text = '',
      st = 0,
      vt = [],
      du;
    voiceTime.forEach(item => {
      const { txt, endTime } = item;
      item.startTime += baseStartTime;
      if (TextDrive.SECTION_SIGN.indexOf(txt.trim()) === -1) {
        // 这里需要单独对数字轴和STL轴特殊处理
        if (txt.trim().length > 1) {
          this._parseSpecial(vt, item, baseStartTime);
        } else {
          text += txt;
          vt.push(item);
        }
      } else {
        res.push({
          startTime: st + baseStartTime,
          absoluteStartTime: st,
          duration: endTime - st,
          txt: text,
          voiceTime: vt,
          voiceArr: [],
        });
        text = '';
        st = endTime;
        vt = [];
      }
    });
    // 最后一组数据不能没有添加
    const { endTime } = voiceTime[voiceTime.length - 1];
    du = endTime;
    if (vt.length) {
      res.push({
        startTime: st + baseStartTime,
        absoluteStartTime: st,
        duration: endTime - st,
        txt: text,
        voiceTime: vt,
        voiceArr: [],
      });
    }
    const buffer = new Int8Array(voiceAB); // 这里需要去除第一段的头部信息,把头部信息分给后边的每一组
    res.forEach(item => {
      const { absoluteStartTime, duration } = item;
      let startIndex = Math.floor((absoluteStartTime / du) * buffer.byteLength);
      startIndex = startIndex - (startIndex % Number(4));
      let endIndex = Math.floor(((absoluteStartTime + duration) / du) * buffer.byteLength);
      endIndex = endIndex - (endIndex % Number(4));
      // endIndex对齐到4bit
      const bufferData = buffer.slice(startIndex, endIndex).buffer;
      const voiceData = addBufferWavHeader(bufferData);
      item.url = URL.createObjectURL(new Blob([voiceData], { type: 'audio/wav' }));
      item.rate = duration / du;
    });
    this.sliderArr = res;
    this.duration = du;
  }
  // 用于计算单个文本的位置
  calcTextPosition(sliderArrItem, itemWidth) {
    const { voiceTime, startTime: s1, duration, voiceArr } = sliderArrItem;
    voiceArr.splice(0, voiceArr.length);
    voiceTime.forEach((item1, index1) => {
      const { startTime: s2, txt } = item1;
      const left = ((s2 - s1) / duration) * itemWidth; // 这里只需要计算left值,相对于当前块的开始
      voiceArr.push({ txt, left, id: index1 });
    });
  }
  // 用于计算特殊字符的位置(数字和STL(停顿))
  _parseSpecial(vt, item, baseStartTime) {
    // vt里面存储的是数据本身
    const { txt, startTime, endTime } = item;
    if (txt !== 'SIL') {
      const duration = endTime + baseStartTime - startTime;
      const textArr = txt.split('');
      const count = textArr.length;
      const oneDuration = duration / count;
      textArr.forEach((item, index) => {
        vt.push({
          txt: item,
          startTime: index * oneDuration + startTime,
          endTime: (index + 1) * oneDuration + startTime, // endTime渲染的时候用不到
        });
      });
    }
  }
}
// 音频驱动轴
class AudioDrive extends TimeLine {
  name = 'audioDrive';
  baseStartTime = 0;
  audioName = '';
  audioSrc = '';
  disable = {
    row: true,
    col: true,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  sliderArr = []; // 多元素的列表
  multi = true;
  fatherName = 'vtuber';
  fatherStartTime = 0;
  partUpdateAttr = ['audioName', 'audioSrc', 'sliderArr', 'baseStartTime'];
  constructor(params) {
    super(params);
    const { audioName = '', audioSrc = '', baseStartTime = 0 } = params;
    Object.assign(this, { baseStartTime, audioName, audioSrc });
    this._generateSliderArr(); // 这里用来解析生成sliderArr
    this._initAllTime();
    this._parseIconConfig(params);
  }
  // 渲染频谱图
  async renderSpectrum(allWidth) {
    const MAX_HEIGHT = 38; // 最大柱形高度
    const PADDING_WIDTH = 8;
    const { sliderArr } = this;
    const renderWidth = allWidth * sliderArr[0].rate - PADDING_WIDTH;
    return await calcSpectrumWorker(renderWidth, MAX_HEIGHT, this.audioSrc, null);
  }
  // 根据时长计算有多少个片段
  _generateSliderArr() {
    const { videoDuration, duration: dt, sliderArr, audioName, baseStartTime } = this;
    sliderArr.splice(0, sliderArr.length);
    let duration = dt;
    // 这里判断一下背景音乐市场是否超出视频时长
    const realDuration = duration > videoDuration ? videoDuration : duration;
    sliderArr.push({
      startTime: baseStartTime,
      duration: realDuration,
      rate: realDuration / videoDuration,
      name: audioName,
    });
  }
  // 当时长变化时的处理
  videoDurationChange() {
    this._generateSliderArr();
  }
}
// AI金融模板类
class AiFinTemplate extends TimeLine {
  name = 'aiFinTemplate';
  coverSrc = ''; // 图片地址
  templateName = ''; // 模板名称
  disable = {
    row: true,
    col: false,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['delete'];
  partUpdateAttr = ['coverSrc', 'templateName'];
  constructor(params) {
    super(params);
    this.coverSrc = params.coverSrc || '';
    this.templateName = params.templateName || '';
    this._initAllTime();
    this._parseIconConfig(params);
  }
}
// 可视化组件
class Chart extends TimeLine {
  name = 'chart';
  graphicsSrc = ''; // 图片地址
  disable = {
    row: false,
    col: false,
    time: false,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
  };
  // 图标的展示和隐藏
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 1, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.收缩 2.展开
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  };
  contextMenuList = ['copy', 'delete'];
  partUpdateAttr = ['graphicsSrc'];
  constructor(params) {
    super(params);
    this.graphicsSrc = params.graphicsSrc || '';
    this._initAllTime();
    this._parseIconConfig(params);
    this.loadChart();
  }
  loadChart() {
    if (this.graphicsSrc) {
      return;
    }
    ChartManager.on(this.mark, chartData => {
      if (chartData.status === 1) {
        this.graphicsSrc = chartData.src;
      }
    });
  }
}
// 情绪化数字人轴
class Emotion extends TimeLine {
  name = 'emotion';
  sliderArr = []; // 滑块列表
  disable = {
    row: false,
    col: true,
    time: true,
    dbClick: false, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: false, // 可以hover预览视频
    exceed: true, // 禁止超出时长
  };
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.关闭声音
    contract: 0, // 0:禁止 1.展开 2.收缩
    selectable: 1, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中
  }; // 图标的展示和隐藏
  multi = true; // 多元素
  contextMenuList = ['copy', 'delete', 'deleteAll'];
  fatherName = 'vtuber';
  fatherStartTime = 0;
  partUpdateAttr = ['sliderArr'];
  constructor(params) {
    super(params);
    this.sliderArr = this._parseSliderArr(params.emotionTimeLine);
    Object.assign(this, {});
    this._initAllTime();
  }
  // 解析单轴多元素的情绪轴
  _parseSliderArr(emotionTimLine) {
    return emotionTimLine.map((item, index) => {
      const { startTime, duration, name, previewUrl, videoUrl } = item;
      return {
        uid: generateUUID(),
        startTime,
        duration,
        name,
        previewUrl,
        videoUrl,
        index,
      };
    });
  }
}
// 多人数字人驱动轴
class DoubleDrive extends TimeLine {
  name = 'doubleDrive';
  disable = {
    row: false,
    col: true,
    time: true,
    dbClick: true, // 双击
    clickItem: false, // 单击后画面选中后
    clickIcon: false, // 点击左侧图标
    previewVideo: true, // 可以hover预览视频
    exceed: false, // 禁止超出时长
  }; // 禁止
  iconDisable = {
    icon: 1, // 0 |1  1可点击
    show: 0, // 0: 禁止 1.显示  2.隐藏  // 0状态和不显示状态冲突
    sound: 0, // 0:禁止 1:有声 2.禁止声音
    contract: 0, // 0:禁止 1.展开 2.收缩
    selectable: 0, // 画布中选中 0:禁止修改 1:可以选中 2:不可选中, 这个是全部禁用的标志,如果是2,则编辑操作全部禁用
  }; // 图标的展示和隐藏
  multi = true;
  sliderArr = []; // 一行内的其他元素
  fatherName = 'vtuber';
  channel = DOUBLE_DRIVER_POS.LEFT; // 定义驱动轴的位置
  showOtherIcon = true;
  vtuberName = '';
  avatarUrl = '';
  fatherStartTime = 0;
  partUpdateAttr = ['sliderArr', 'channel', 'vtuberName', 'avatarUrl'];
  constructor(params) {
    super(params);
    const { channel, broadcastList, name, avatarUrl } = params;
    Object.assign(this, { channel, vtuberName: name, avatarUrl });
    this._initAllTime();
    this._parseIconConfig(params);
    this._generateSliderArr(broadcastList);
  }
  // 解析子轴片段
  _generateSliderArr(broadcastList) {
    const { sliderArr } = this;
    sliderArr.splice(0, sliderArr.length);
    broadcastList.forEach((item, index) => {
      const { mode, startTime, duration, url, name, voiceTime, content, mark } = item;
      if (mode === 'text') {
        sliderArr.push({
          ...{ mode, startTime, duration, voiceTime },
          ...{ content, voiceArr: [], url, uid: generateUUID(), mark, index },
        });
      } else {
        sliderArr.push({ mode, startTime, duration, url, name, uid: generateUUID(), mark, index });
      }
    });
  }
  // 用于计算单个文本的位置
  calcTextPosition(sliderArrItem, itemWidth) {
    const { duration, voiceTime, voiceArr } = sliderArrItem;
    voiceArr.splice(0, voiceArr.length);
    voiceTime.forEach((item1, index1) => {
      const { startTime: s2, txt } = item1;
      const left = (s2 / duration) * itemWidth; // 这里只需要计算left值,相对于当前块的开始
      voiceArr.push({ txt, left, id: index1 });
    });
  }
}
export default {
  Vtuber,
  BgMusic,
  Sticker,
  Signature,
  Graphics,
  VideoType,
  Shape,
  Action,
  Background3d,
  Camera,
  TextDrive,
  AudioDrive,
  AiFinTemplate,
  Chart,
  Emotion,
  DoubleDrive,
};
